package web

import (
	"fmt"
	"log"
	"net/http"
)

type HandlerFunc func(ctx *Context)

var _ Server = &HTTPServer{}

type Server interface {
	http.Handler
	Start(addr string) error
	addRoute(method string, path string, handler HandlerFunc, mdls ...Middleware)
}

type HTTPServer struct {
	router
	mdls []Middleware

	log       func(msg string, args ...any)
	tplEngine TemplateEngine

	serveWithMiddleware HandlerFunc
}

type HTTPServerOption func(*HTTPServer)

func NewHTTPServer(opts ...HTTPServerOption) *HTTPServer {
	res := &HTTPServer{
		router: newRouter(),
		log: func(msg string, args ...any) {
			fmt.Printf(msg, args...)
		},
	}

	for _, o := range opts {
		o(res)
	}

	// 在创建实例的时候组装全局的 middleware，需要增加一个方法类型的字段 serveWithMiddleware
	// 如果放到 ServeHTTP 方法中，每次请求到来都要重复组装一次，效率不高，
	// 但也失去了中间件热插拔的功能
	root := res.serve
	for i := len(res.mdls) - 1; i >= 0; i-- {
		root = res.mdls[i](root)
	}

	var m Middleware = func(next HandlerFunc) HandlerFunc {
		return func(ctx *Context) {
			next(ctx)
			res.flashResp(ctx)
		}
	}
	root = m(root)
	res.serveWithMiddleware = root
	return res
}

func ServerWithTemplateEngine(tplEngine TemplateEngine) HTTPServerOption {
	return func(h *HTTPServer) {
		h.tplEngine = tplEngine
	}
}

func ServerWithMiddleware(mdl Middleware) HTTPServerOption {
	return func(h *HTTPServer) {
		h.mdls = append(h.mdls, mdl)
	}
}

// 添加路由的同时添加中间件
func (s *HTTPServer) Use(method string, path string, handler HandlerFunc, mdls ...Middleware) {
	s.addRoute(method, path, handler, mdls...)
}

func (s *HTTPServer) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
	ctx := Context{
		Resp:      resp,
		Req:       req,
		tplEngine: s.tplEngine,
	}
	s.serveWithMiddleware(&ctx)

	// root := s.serve
	// for i := len(s.mdls) - 1; i >= 0; i-- {
	// 	root = s.mdls[i](root)
	// }

	// var m Middleware = func(next HandlerFunc) HandlerFunc {
	// 	return func(ctx *Context) {
	// 		next(ctx)
	// 		s.flashResp(ctx)
	// 	}
	// }
	// root = m(root)
	// root(&ctx)
}

func (s *HTTPServer) Start(addr string) error {
	return http.ListenAndServe(addr, s)
}

func (s *HTTPServer) Post(path string, handler HandlerFunc) {
	s.addRoute(http.MethodPost, path, handler)
}

func (s *HTTPServer) Get(path string, handler HandlerFunc) {
	s.addRoute(http.MethodGet, path, handler)
}

func (s *HTTPServer) serve(ctx *Context) {
	mi, ok := s.findRoute(ctx.Req.Method, ctx.Req.URL.Path)
	if !ok || mi == nil || mi.n.handler == nil {
		// ctx.Resp.WriteHeader(404)
		// ctx.Resp.Write([]byte("Not Found"))
		ctx.RespStatusCode = 404
		return
	}

	ctx.PathParams = mi.pathParams
	ctx.MathedRoute = mi.n.route

	root := mi.n.handler
	// 调用匹配上的中间件，
	for i := len(mi.mdls) - 1; i >= 0; i-- {
		root = mi.mdls[i](root)
	}
	root(ctx)
}

func (s *HTTPServer) flashResp(ctx *Context) {
	if ctx.RespStatusCode > 0 {
		ctx.Resp.WriteHeader(ctx.RespStatusCode)
	}
	_, err := ctx.Resp.Write(ctx.RespData)
	if err != nil {
		log.Fatalln("输出响应失败", err)
	}
}
